using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Jurassic;
using Kiwi.Node.Modules;
using Kiwi.Node.Modules.Builtin;
using Kiwi.Node.Modules.Http;
using Console = System.Console;

namespace Kiwi.Node
{
    public class Application : IApplication
    {
        public Application()
        {
            RootFolder = Environment.CurrentDirectory;
            StdOut = Console.Out;
            StdErr = Console.Error;
            Engine = new ScriptEngine {CompatibilityMode = CompatibilityMode.ECMAScript3};
            Engine.Object.Construct();
            Events = new EventQueue();
            ProcessObject = new Process(this);
            ModuleResolvers = new List<IModuleResolver>
                                  {
                                      new ModuleResolver
                                          {
                                              {"process", a => ProcessObject},
                                              {"jsruntime", a => new JsRuntime(a)},
                                              {"http", a => new Http(a)},
                                              {"textfile", a => new TextFile(a)},
                                              {"sql", a => new Sql(a)},

                                              //{"events", c => CreateEmbeddedScriptModule("events")}
                                          },
                                      new LibModuleResolver(Assembly.GetExecutingAssembly(), "Kiwi.Node.Lib"),
                                      new ScriptModuleResolver()
                                  };
            MainModule = CreateModule(new StringScriptSource("(0);"));
        }

        protected IModule MainModule { get; private set; }

        #region IApplication Members

        public string RootFolder { get; set; }
        public TextWriter StdErr { get; set; }
        public TextWriter StdOut { get; set; }
        public ScriptEngine Engine { get; set; }

        public IEventQueue Events { get; set; }

        public ScriptEngine CreateScriptEngine()
        {
            var engine = new ScriptEngine() { CompatibilityMode = CompatibilityMode.ECMAScript3 };

            // Array.isArray gives problems to a lot of modules
            engine.Array["isArray"] = Engine.Function.Construct("value", "return jsruntime.isArray(value);");
            return engine;
        }

        public List<IModuleResolver> ModuleResolvers { get; private set; }

        public Process ProcessObject { get; private set; }

        public IModule CreateModule(ScriptSource scriptSource)
        {
            return new Module(this, scriptSource);
        }

        public object Resolve(string moduleName)
        {
            return (from mr in ModuleResolvers
                    let rm = mr.TryResolveDynamic(this, this.RootFolder, moduleName)
                    where rm != null
                    select rm.Resolve(this)).FirstOrDefault();
        }

        #endregion
    }
}